package com.childenglish.controller;

import com.childenglish.entity.SysUser;
import com.childenglish.mapper.SysUserMapper;
import com.childenglish.service.EmailService;
import com.childenglish.utils.DataEncryptionUtils;
import com.childenglish.utils.PasswordEncoderUtil;
import com.childenglish.utils.R;
import com.childenglish.utils.SecurityAuditLogger;
import com.childenglish.utils.UserDataHelper;
import com.childenglish.utils.ValidationPatterns;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import javax.validation.Valid;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.Size;
import javax.validation.constraints.Pattern;
import com.childenglish.validation.PasswordMatch;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import java.util.HashMap;
import java.util.Map;
import java.util.Random;
import java.util.concurrent.TimeUnit;

/**
 * 找回密码控制器
 */
@RestController
@RequestMapping("/api")
public class ForgotPasswordController {

    private static final Logger logger = LoggerFactory.getLogger(ForgotPasswordController.class);

    @Autowired
    private SysUserMapper sysUserMapper;

    @Autowired
    private CaptchaController captchaController;

    @Autowired(required = false)
    private RedisTemplate<String, Object> redisTemplate;

    @Autowired
    private EmailService emailService;

    /**
     * 发送找回密码验证码
     * 支持通过用户名、邮箱或手机号找回
     */
    @PostMapping("/forgot-password/send-code")
    public R sendResetCode(@Valid @RequestBody SendCodeRequest request, HttpSession session) {
        try {
            // 验证图形验证码（业务逻辑校验，保留）
            if (!captchaController.verifyCaptchaFromSession(session, request.getCaptcha())) {
                return R.error("验证码错误或已过期");
            }

            // 查找用户（支持用户名、邮箱、手机号）
            SysUser user = null;
            String identifier = request.getIdentifier().trim();
            
            logger.info("开始查找用户，输入标识: {}", identifier);

            // 判断是邮箱、手机号还是用户名
            if (identifier.contains("@")) {
                // 邮箱格式 - 数据库中的邮箱可能是加密存储的，也可能是明文存储的
                logger.info("识别为邮箱格式，开始查询");
                
                // 先尝试加密查询（新数据）
                String encryptedEmail = DataEncryptionUtils.encryptSensitiveField(identifier);
                logger.debug("邮箱加密后: {}", encryptedEmail);
                user = sysUserMapper.findByEmail(encryptedEmail);
                
                // 如果加密查询找不到，尝试明文查询（兼容旧数据）
                if (user == null) {
                    logger.info("加密查询未找到，尝试明文查询（兼容旧数据）");
                    user = sysUserMapper.findByEmail(identifier);
                }
                
                if (user != null) {
                    logger.info("通过邮箱找到用户: {}", user.getUsername());
                } else {
                    logger.warn("通过邮箱未找到用户（已尝试加密和明文查询）: {}", identifier);
                }
            } else if (java.util.regex.Pattern.matches("^1[3-9]\\d{9}$", identifier)) {
                // 手机号格式（11位数字，1开头） - 数据库中的手机号可能是加密存储的，也可能是明文存储的
                logger.info("识别为手机号格式，开始查询");
                
                // 先尝试加密查询（新数据）
                String encryptedPhone = DataEncryptionUtils.encryptSensitiveField(identifier);
                logger.debug("手机号加密后: {}", encryptedPhone);
                user = sysUserMapper.findByPhone(encryptedPhone);
                
                // 如果加密查询找不到，尝试明文查询（兼容旧数据）
                if (user == null) {
                    logger.info("加密查询未找到，尝试明文查询（兼容旧数据）");
                    user = sysUserMapper.findByPhone(identifier);
                }
                
                if (user != null) {
                    logger.info("通过手机号找到用户: {}", user.getUsername());
                } else {
                    logger.warn("通过手机号未找到用户（已尝试加密和明文查询）: {}", identifier);
                    // 尝试通过用户名查找（可能用户输入的是用户名但格式像手机号）
                    logger.info("尝试通过用户名查找: {}", identifier);
                    user = sysUserMapper.findByUsername(identifier);
                }
            } else {
                // 用户名
                logger.info("识别为用户名格式，开始查询");
                user = sysUserMapper.findByUsername(identifier);
                if (user != null) {
                    logger.info("通过用户名找到用户: {}", user.getUsername());
                } else {
                    logger.warn("通过用户名未找到用户: {}", identifier);
                }
            }

            if (user == null) {
                // 为了安全，不明确提示用户不存在
                logger.warn("未找到用户，标识: {}", identifier);
                return R.ok("如果该账户存在，验证码已发送");
            }

            // 检查用户是否有邮箱或手机号
            if ((user.getEmail() == null || user.getEmail().trim().isEmpty()) &&
                (user.getPhone() == null || user.getPhone().trim().isEmpty())) {
                return R.error("该账户未绑定邮箱或手机号，无法找回密码");
            }

            // 生成6位数字验证码
            String resetCode = generateResetCode();
            
            // 存储验证码到Redis或Session（10分钟过期）
            String sessionId = session.getId();
            String codeKey = "reset_code:" + sessionId + ":" + user.getId();
            
            if (redisTemplate != null) {
                redisTemplate.opsForValue().set(codeKey, resetCode, 10, TimeUnit.MINUTES);
            } else {
                session.setAttribute("reset_code_" + user.getId(), resetCode);
                session.setAttribute("reset_code_time_" + user.getId(), System.currentTimeMillis());
            }

            // 存储用户ID到Session（用于后续验证）
            session.setAttribute("reset_user_id", user.getId());

            // 发送验证码
            // 获取邮箱和手机号（可能是加密的，也可能是明文的）
            String decryptedEmail = null;
            String decryptedPhone = null;
            if (user.getEmail() != null && !user.getEmail().trim().isEmpty()) {
                String email = user.getEmail();
                // 尝试解密，如果解密失败说明是明文，直接使用
                try {
                    decryptedEmail = DataEncryptionUtils.decryptSensitiveField(email);
                    logger.debug("邮箱解密成功: {}", decryptedEmail);
                } catch (Exception e) {
                    // 解密失败，说明是明文，直接使用
                    decryptedEmail = email;
                    logger.debug("邮箱是明文，直接使用: {}", email);
                }
            }
            if (user.getPhone() != null && !user.getPhone().trim().isEmpty()) {
                String phone = user.getPhone();
                // 尝试解密，如果解密失败说明是明文，直接使用
                try {
                    decryptedPhone = DataEncryptionUtils.decryptSensitiveField(phone);
                    logger.debug("手机号解密成功: {}", decryptedPhone);
                } catch (Exception e) {
                    // 解密失败，说明是明文，直接使用
                    decryptedPhone = phone;
                    logger.debug("手机号是明文，直接使用: {}", phone);
                }
            }
            
            String contact = decryptedEmail != null && !decryptedEmail.trim().isEmpty() 
                ? decryptedEmail 
                : decryptedPhone;
            
            boolean sendSuccess = false;
            if (decryptedEmail != null && !decryptedEmail.trim().isEmpty()) {
                // 发送邮件验证码（使用解密后的邮箱地址）
                sendSuccess = emailService.sendPasswordResetCode(decryptedEmail, user.getUsername(), resetCode);
            } else if (decryptedPhone != null && !decryptedPhone.trim().isEmpty()) {
                // 如果是手机号，暂时输出到控制台（后续可集成短信服务）
                System.out.println("========================================");
                System.out.println("找回密码验证码（短信服务未配置）");
                System.out.println("用户: " + user.getUsername());
                System.out.println("手机号: " + decryptedPhone);
                System.out.println("验证码: " + resetCode);
                System.out.println("有效期: 10分钟");
                System.out.println("========================================");
                sendSuccess = true;
            }

            // 检查是否发送成功
            if (!sendSuccess) {
                logger.error("验证码发送失败，用户: {}, 邮箱: {}, 手机号: {}", 
                    user.getUsername(), decryptedEmail, decryptedPhone);
                return R.error("验证码发送失败，请稍后重试");
            }

            // 记录安全日志
            HttpServletRequest httpRequest = ((ServletRequestAttributes) RequestContextHolder
                .currentRequestAttributes()).getRequest();
            String ipAddress = SecurityAuditLogger.getClientIp(httpRequest);
            SecurityAuditLogger.logPasswordReset(user.getUsername(), true, ipAddress);

            // 确保 contact 不为 null
            String maskedContact = contact != null ? maskContact(contact) : "***";
            
            Map<String, Object> data = new HashMap<>();
            data.put("message", "验证码已发送");
            data.put("contact", maskedContact); // 脱敏显示
            data.put("expiresIn", 600); // 10分钟，单位秒

            return R.ok("验证码已发送").data(data);
        } catch (Exception e) {
            e.printStackTrace();
            return R.error("发送验证码失败: " + e.getMessage());
        }
    }

    /**
     * 重置密码
     */
    @PostMapping("/forgot-password/reset")
    public R resetPassword(@Valid @RequestBody ResetPasswordRequest request, HttpSession session) {
        try {
            // 获取用户ID
            Long userId = (Long) session.getAttribute("reset_user_id");
            if (userId == null) {
                return R.error("请先获取验证码");
            }

            // 验证重置验证码
            String codeKey = "reset_code:" + session.getId() + ":" + userId;
            String storedCode = null;

            if (redisTemplate != null) {
                Object value = redisTemplate.opsForValue().get(codeKey);
                if (value != null) {
                    storedCode = value.toString();
                }
            } else {
                Object codeObj = session.getAttribute("reset_code_" + userId);
                if (codeObj != null) {
                    storedCode = codeObj.toString();
                    // 检查是否过期（10分钟）
                    Long codeTime = (Long) session.getAttribute("reset_code_time_" + userId);
                    if (codeTime != null && System.currentTimeMillis() - codeTime > 10 * 60 * 1000) {
                        session.removeAttribute("reset_code_" + userId);
                        session.removeAttribute("reset_code_time_" + userId);
                        return R.error("验证码已过期，请重新获取");
                    }
                }
            }

            if (storedCode == null) {
                return R.error("验证码已过期，请重新获取");
            }

            if (!storedCode.equals(request.getResetCode())) {
                return R.error("验证码错误");
            }

            // 获取用户信息
            SysUser user = sysUserMapper.findById(userId);
            if (user == null) {
                return R.error("用户不存在");
            }

            // 解密前端加密的密码（先解密再验证）
            String rawPassword = UserDataHelper.decryptPassword(request.getNewPassword());
            String rawConfirmPassword = UserDataHelper.decryptPassword(request.getConfirmPassword());
            
            logger.info("重置密码 - 用户ID: {}, 密码长度: {}", userId, rawPassword != null ? rawPassword.length() : 0);

            // 验证新密码不能为空
            if (rawPassword == null || rawPassword.trim().isEmpty()) {
                return R.error("新密码不能为空");
            }

            // 验证新密码强度（在解密后验证，业务逻辑校验）
            if (!ValidationPatterns.PASSWORD_PATTERN.matcher(rawPassword).matches()) {
                logger.warn("密码格式验证失败 - 长度: {}, 包含字母: {}, 包含数字: {}", 
                    rawPassword.length(),
                    rawPassword.matches(".*[A-Za-z].*"),
                    rawPassword.matches(".*\\d.*"));
                return R.error("密码必须为8-20位，且包含字母和数字");
            }

            // 验证两次密码是否一致（在解密后验证）
            if (!rawPassword.equals(rawConfirmPassword)) {
                return R.error("两次密码输入不一致");
            }

            // 使用BCrypt加密新密码
            String encodedPassword = PasswordEncoderUtil.encode(rawPassword);
            
            // 更新密码
            sysUserMapper.updatePassword(userId, encodedPassword);

            // 清除验证码和用户ID
            if (redisTemplate != null) {
                redisTemplate.delete(codeKey);
            } else {
                session.removeAttribute("reset_code_" + userId);
                session.removeAttribute("reset_code_time_" + userId);
            }
            session.removeAttribute("reset_user_id");

            // 记录安全日志
            HttpServletRequest httpRequest = ((ServletRequestAttributes) RequestContextHolder
                .currentRequestAttributes()).getRequest();
            String ipAddress = SecurityAuditLogger.getClientIp(httpRequest);
            SecurityAuditLogger.logPasswordReset(user.getUsername(), true, ipAddress);

            return R.ok("密码重置成功，请使用新密码登录");
        } catch (Exception e) {
            e.printStackTrace();
            return R.error("重置密码失败: " + e.getMessage());
        }
    }

    /**
     * 生成6位数字验证码
     */
    private String generateResetCode() {
        Random random = new Random();
        int code = 100000 + random.nextInt(900000); // 生成100000-999999之间的数字
        return String.valueOf(code);
    }

    /**
     * 脱敏显示联系方式
     */
    private String maskContact(String contact) {
        if (contact == null || contact.isEmpty()) {
            return "";
        }
        if (contact.contains("@")) {
            // 邮箱：abc@example.com -> a**@example.com
            int atIndex = contact.indexOf("@");
            if (atIndex > 1) {
                return contact.charAt(0) + "**" + contact.substring(atIndex);
            }
            return "***" + contact.substring(atIndex);
        } else {
            // 手机号：13800138000 -> 138****8000
            if (contact.length() == 11) {
                return contact.substring(0, 3) + "****" + contact.substring(7);
            }
            return "****";
        }
    }

    /**
     * 发送验证码请求
     */
    public static class SendCodeRequest {
        @NotBlank(message = "用户名/邮箱/手机号不能为空")
        private String identifier;

        @NotBlank(message = "验证码不能为空")
        private String captcha;

        public String getIdentifier() { return identifier; }
        public void setIdentifier(String identifier) { this.identifier = identifier; }
        public String getCaptcha() { return captcha; }
        public void setCaptcha(String captcha) { this.captcha = captcha; }
    }

    /**
     * 重置密码请求
     * 注意：密码字段不添加验证注解，因为密码是加密传输的，需要在方法内部解密后再验证
     */
    @PasswordMatch(password = "newPassword", confirmPassword = "confirmPassword", message = "两次密码输入不一致")
    public static class ResetPasswordRequest {
        @NotBlank(message = "验证码不能为空")
        private String resetCode;

        @NotBlank(message = "新密码不能为空")
        // 注意：不在这里验证密码格式，因为密码是加密传输的
        // 密码格式验证在方法内部解密后进行
        private String newPassword;

        @NotBlank(message = "确认密码不能为空")
        private String confirmPassword;

        public String getResetCode() { return resetCode; }
        public void setResetCode(String resetCode) { this.resetCode = resetCode; }
        public String getNewPassword() { return newPassword; }
        public void setNewPassword(String newPassword) { this.newPassword = newPassword; }
        public String getConfirmPassword() { return confirmPassword; }
        public void setConfirmPassword(String confirmPassword) { this.confirmPassword = confirmPassword; }
    }
}

